package com.sip.stream.utils.zfy.encoder;

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.util.Log;

import com.sip.stream.utils.zfy.GSMediaCodecData;
import com.sip.stream.utils.zfy.yuv.YUVToolFactory;

import java.nio.ByteBuffer;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

public class GSMediaCodecAsyncCallBack extends MediaCodec.Callback {
    private static final String TAG = "GSMediaCodecAsyncCallBack";

    private static final int TIME_OUT = 1000;
    private boolean isStop;
    private GSMediaCodecAsyncCallBackListener listener;
    private MediaCodec mediaCodec;
    private boolean needRecycle;
    private BlockingDeque<GSMediaCodecData> waitDeque = new LinkedBlockingDeque(10);
    boolean stoped = false;

    public interface GSMediaCodecAsyncCallBackListener {
        void encodeVideoSuccess(ByteBuffer byteBuffer, MediaCodec.BufferInfo bufferInfo);

        void setOutputFormat(MediaFormat mediaFormat);

        void stopMediaCodec();
    }

    public GSMediaCodecAsyncCallBack(MediaCodec mediaCodec, GSMediaCodecAsyncCallBackListener gSMediaCodecAsyncCallBackListener, boolean needRecycle) {
        this.mediaCodec = mediaCodec;
        this.listener = gSMediaCodecAsyncCallBackListener;
        this.needRecycle = needRecycle;
    }

    public void setOutputFormat(MediaFormat mediaFormat) {
        GSMediaCodecAsyncCallBackListener gSMediaCodecAsyncCallBackListener = this.listener;
        if (gSMediaCodecAsyncCallBackListener != null) {
            gSMediaCodecAsyncCallBackListener.setOutputFormat(mediaFormat);
        }
    }

    public void encodeVideoSuccess(ByteBuffer byteBuffer, MediaCodec.BufferInfo bufferInfo) {
        GSMediaCodecAsyncCallBackListener gSMediaCodecAsyncCallBackListener = this.listener;
        if (gSMediaCodecAsyncCallBackListener != null) {
            gSMediaCodecAsyncCallBackListener.encodeVideoSuccess(byteBuffer, bufferInfo);
        }
    }

    public void stopMediaCodec() {
        GSMediaCodecAsyncCallBackListener gSMediaCodecAsyncCallBackListener = this.listener;
        if (gSMediaCodecAsyncCallBackListener != null) {
            gSMediaCodecAsyncCallBackListener.stopMediaCodec();
            this.listener = null;
        }
    }

    public boolean encode(byte[] bArr, long j) {
        GSMediaCodecData gSMediaCodecData = new GSMediaCodecData();
        gSMediaCodecData.data = bArr;
        gSMediaCodecData.timeStamp = j;
        if (this.waitDeque.offer(gSMediaCodecData) || !this.needRecycle) {
            return true;
        }
        YUVToolFactory.recycleData(bArr);
        return true;
    }

    @Override
    public void onInputBufferAvailable(MediaCodec mediaCodec, int index) {
        if (index >= 0) {
            if (this.isStop) {
                if (this.stoped) {
                    return;
                }
                this.stoped = true;
                this.mediaCodec.queueInputBuffer(index, 0, 0, 0L, 4);
                Log.i(TAG, "queueInputBuffer BUFFER_FLAG_END_OF_STREAM");
                return;
            }
            try {
                GSMediaCodecData take = this.waitDeque.take();
                byte[] bArr = take.data;
                long j = take.timeStamp;
                if (bArr == null || j < 1) {
                    this.mediaCodec.queueInputBuffer(index, 0, 0, 0L, 4);
                    return;
                }
                ByteBuffer inputBuffer = this.mediaCodec.getInputBuffer(index);
                if (inputBuffer == null || inputBuffer.capacity() < bArr.length) {
                    Log.e(TAG, "inputBuffer error");
                    return;
                }
                inputBuffer.clear();
                inputBuffer.put(bArr);
                try {
                    this.mediaCodec.queueInputBuffer(index, 0, bArr.length, j, 0);
                } catch (Exception e) {
                    Log.e(TAG, "" + e.getMessage());
                    e.printStackTrace();
                }
                if (this.needRecycle) {
                    YUVToolFactory.recycleData(bArr);
                }
            } catch (InterruptedException unused) {
            }
        }
    }

    @Override
    public void onOutputBufferAvailable(MediaCodec mediaCodec, int i, MediaCodec.BufferInfo bufferInfo) {
        if (bufferInfo.flags == 2) {
            ByteBuffer outputBuffer = this.mediaCodec.getOutputBuffer(i);
            outputBuffer.position(bufferInfo.offset);
            outputBuffer.limit(bufferInfo.offset + bufferInfo.size);
            encodeVideoSuccess(copyDirectByteBuffer(outputBuffer), bufferInfo);
            this.mediaCodec.releaseOutputBuffer(i, false);
        } else if (bufferInfo.flags == 4) {
            Log.i(TAG, "flags == BUFFER_FLAG_END_OF_STREAM");
            stopMediaCodec();
        } else if (i < 0 || bufferInfo.size <= 0) {
            if (i == -2) {
                setOutputFormat(this.mediaCodec.getOutputFormat());
            }
        } else {
            ByteBuffer outputBuffer2 = this.mediaCodec.getOutputBuffer(i);
            outputBuffer2.position(bufferInfo.offset);
            outputBuffer2.limit(bufferInfo.offset + bufferInfo.size);
            encodeVideoSuccess(copyDirectByteBuffer(outputBuffer2), bufferInfo);
            this.mediaCodec.releaseOutputBuffer(i, false);
        }
    }

    @Override
    public void onError(MediaCodec mediaCodec, MediaCodec.CodecException codecException) {
        codecException.printStackTrace();
    }

    @Override
    public void onOutputFormatChanged(MediaCodec mediaCodec, MediaFormat mediaFormat) {
        setOutputFormat(mediaFormat);
    }

    public void setStop(boolean isStop) {
        this.isStop = isStop;
        GSMediaCodecData gSMediaCodecData = new GSMediaCodecData();
        gSMediaCodecData.timeStamp = -1L;
        this.waitDeque.offer(gSMediaCodecData);
    }

    protected ByteBuffer copyDirectByteBuffer(ByteBuffer byteBuffer) {
        ByteBuffer allocateDirect = ByteBuffer.allocateDirect(byteBuffer.remaining());
        allocateDirect.put(byteBuffer);
        allocateDirect.order(byteBuffer.order());
        allocateDirect.position(0);
        return allocateDirect.asReadOnlyBuffer();
    }
}
